﻿using System.Text;
using iMarkdown.Blocks;
using iMarkdown.Tokens;

namespace iMarkdown;

public class MarkdownParser(string markdown)
{
    private string[] MarkdownLines { get; } =
        markdown.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);

    private static string MarkdownChars => "*_~`[]()\\";

    public List<Block> Parse(string markdown = "")
    {
        var lines = MarkdownLines.AsSpan();
        if (!string.IsNullOrEmpty(markdown))
            lines = markdown.Split("\n", StringSplitOptions.RemoveEmptyEntries).AsSpan();
        var blocks = new List<Block>();
        for (int i = 0; i < lines.Length; i++)
        {
            var line = lines[i];

            // 处理分隔符
            if (line.All(x => x is '-' or '*' or '_'))
            {
                blocks.Add(new DividerBlock());
                continue;
            }


            // 处理代码块
            if (line.StartsWith("```"))
            {
                int j = i + 1;
                while (j < lines.Length)
                {
                    if (lines[j].StartsWith("```")) break;
                    j++;
                }

                if (lines[j].StartsWith("```"))
                {
                    var codeBlock = new CodeBlock
                    {
                        Language = lines[i][3..]
                    };
                    i++;
                    while (i < j)
                    {
                        codeBlock.Context += lines[i] + "\n";
                        i++;
                    }

                    i++;

                    blocks.Add(codeBlock);
                }

                continue;
            }

            if (line.StartsWith('#'))
            {
                var level = 0;
                while (line.StartsWith('#'))
                {
                    level++;
                    line = line[1..];
                }

                blocks.Add(new HeaderBlock() { Context = line.Trim(), Level = level });
                continue;
            }

            if (line.StartsWith('>'))
            {
                var b = Parse(line.TrimStart('>'));
                blocks.Add(new QuoteBlock() { Blocks = b });
                continue;
            }

            blocks.Add(new ParagraphBlock() { Context = line, Blocks = ParseStringLine(line) });
        }

        return blocks;
    }

    private List<Block> ParseStringLine(string markdown)
    {
        var str = "";
        string mark = "";
        var blocks = new List<Block>();
        var token = Tokenizer(markdown);

        for (int i = 0; i < token.Count; i++)
        {
            var model = token[i];
            if (model.Token == MarkdownToken.italic)
            {
                
            }
        }

        if (!string.IsNullOrEmpty(str)) blocks.Add(new StringBlock() { Context = str });
        return blocks;
    }

    public List<TokenModel> Tokenizer(string markdown)
    {
        var line = markdown.AsSpan();
        var tokens = new List<TokenModel>();
        var str = "";
        bool isIg = false;

        for (int i = 0; i < line.Length; i++)
        {
            var c = line[i];
            if (MarkdownChars.Contains(c) && !isIg)
            {
                tokens.Add(new TokenModel(MarkdownToken.paragraph, str, i - str.Length, i - 1));
                str = "";
                switch (c)
                {
                    case '*':
                        tokens.Add(new TokenModel(MarkdownToken.italic, c.ToString(), i, i));
                        break;
                    case '_':
                        tokens.Add(new TokenModel(MarkdownToken.italic, c.ToString(), i, i));
                        break;
                    case '~':
                        tokens.Add(new TokenModel(MarkdownToken.delete, c.ToString(), i, i));
                        break;
                    case '`':
                        tokens.Add(new TokenModel(MarkdownToken.code, c.ToString(), i, i));
                        break;
                    case '[':
                        tokens.Add(new TokenModel(MarkdownToken.l_bracket, c.ToString(), i, i));
                        break;
                    case ']':
                        tokens.Add(new TokenModel(MarkdownToken.r_bracket, c.ToString(), i, i));
                        break;
                    case '(':
                        tokens.Add(new TokenModel(MarkdownToken.l_parentheses, c.ToString(), i, i));
                        break;
                    case ')':
                        tokens.Add(new TokenModel(MarkdownToken.r_parentheses, c.ToString(), i, i));
                        break;
                    case '{':
                        tokens.Add(new TokenModel(MarkdownToken.l_brace, c.ToString(), i, i));
                        break;
                    case '}':
                        tokens.Add(new TokenModel(MarkdownToken.r_brace, c.ToString(), i, i));
                        break;
                }

                isIg = false;
            }
            else if (c == '\\')
            {
                isIg = true;
            }
            else
            {
                str += c;
            }
        }

        return tokens;
    }
}